#include <stdio.h>
#include <stdlib.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>

int main(int argc, char const *argv[])
{
    av_log_set_level(AV_LOG_DEBUG);
    /**
     * 抽取音频数据的步骤
     * 1、处理一些参数
     * 2、打开源文件
     * 3、从源文件中找到音频流
     * 4、打开目标文件的上下文
     * 5、为目标文件，创建一个新的音频流
     * 6、设置目标文件音频流的参数
     * 7、写多媒体文件头到目标文件中
     * 8、从源文件中读取到音频数据写入到目标文件中
     * 9、写多媒体文件尾到目标文件中
     * 10、将申请的资源释放掉
     */

    // 定义的常量
    int ret = -1;
    int idx = -1;
    int stream_idx = 0;
    int i = 0;

    int *stream_map = NULL;

    AVFormatContext *inFmtCtx = NULL;
    AVFormatContext *outFmtCtx = NULL;

    const AVOutputFormat *outFmt = NULL;

    AVPacket pkt;

    // 1、处理一些参数
    const char* src;
    const char* dst;

    double starttime = 0;
    double endtime = 0;
    int64_t *dts_start_time = NULL;
    int64_t *pts_start_time = NULL;

    if (argc < 5) {
        av_log(NULL,AV_LOG_INFO,"arguments must be more than 5\n");
        exit(-1);
    }

    src = argv[1];
    dst = argv[2];
    starttime = atof(argv[3]);
    endtime = atof(argv[4]);

    // 2、打开源文件
    if ((ret = avformat_open_input(&inFmtCtx,src,NULL,NULL)) < 0) {
        av_log(NULL,AV_LOG_ERROR,"%s\n",av_err2str(ret));
        exit(-1);
    }

    // 3、打开目标文件的上下文
    avformat_alloc_output_context2(&outFmtCtx,NULL,NULL,dst);
    if (!outFmtCtx) {
         av_log(NULL,AV_LOG_ERROR,"NO Memory!\n");
         goto _ERROR;
    }

    // 4、创建stream_map
    stream_map = av_calloc(inFmtCtx->nb_chapters,sizeof(int));
    if (!stream_map) {
        av_log(NULL,AV_LOG_ERROR,"NO Memory!\n");
        goto _ERROR;
    }

    for (i = 0; i < inFmtCtx->nb_streams; i++)
    {
        AVStream *inStream = inFmtCtx->streams[i];
        AVStream *outStream = NULL;
        AVCodecParameters *inCodecPar = inStream->codecpar;
        if (inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO &&
            inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO &&
            inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
                stream_map[i] = -1;
                continue;
            }

            stream_map[i] = stream_idx++;

            // 5、为目标文件，创建一个新的音频流
            outStream = avformat_new_stream(outFmtCtx,NULL);
            if (!outStream) {
                av_log(outFmtCtx,AV_LOG_ERROR,"NO Memory!\n");
                goto _ERROR;
            }

            // 6、设置目标文件音频\视频\字幕流的参数
            avcodec_parameters_copy(outStream->codecpar,inStream->codecpar);
            outStream->codecpar->codec_tag = 0;
    }
    
    // 绑定，把输出上下文和目标文件进行绑定
    ret = avio_open2(&outFmtCtx->pb,dst,AVIO_FLAG_WRITE,NULL,NULL);
    if (ret < 0) {
        av_log(outFmtCtx,AV_LOG_ERROR,"%s",av_err2str(ret));
        goto _ERROR;
    }

    // 7、写多媒体文件头到目标文件中
    ret = avformat_write_header(outFmtCtx,NULL);
    if (ret < 0) {
        av_log(outFmtCtx,AV_LOG_ERROR,"%s",av_err2str(ret));
        goto _ERROR;
    }

    // seek到开始位置
    ret = av_seek_frame(inFmtCtx , -1 ,starttime*AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
    if (ret < 0) {
        av_log(outFmtCtx,AV_LOG_ERROR,"%s",av_err2str(ret));
        goto _ERROR;
    }

    dts_start_time = av_calloc(inFmtCtx->nb_streams,sizeof(int64_t));
    for (int t = 0; t < inFmtCtx->nb_streams; t++)
    {
        dts_start_time[t] = -1;
    }
    
    pts_start_time = av_calloc(inFmtCtx->nb_streams,sizeof(int64_t));
    for (int t = 0; t < inFmtCtx->nb_streams; t++)
    {
        pts_start_time[t] = -1;
    }

    // 8、从源文件中读取到音频/视频/字幕数据写入到目标文件中
    while(av_read_frame(inFmtCtx,&pkt) >=0 ) {
        AVStream *inStream,*outStream;

        if (dts_start_time[pkt.stream_index] == -1 && pkt.dts > 0) {
            dts_start_time[pkt.stream_index] = pkt.dts;
        }

        if (pts_start_time[pkt.stream_index] == -1 && pkt.pts > 0) {
            pts_start_time[pkt.stream_index] = pkt.pts;
        }

        inStream = inFmtCtx->streams[pkt.stream_index];

        // 到截取时间的最后了
        if (av_q2d(inStream->time_base) * pkt.pts > endtime) {
            av_log(outFmtCtx,AV_LOG_INFO,"success!\n");
            break;
        }

        if (stream_map[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }
        pkt.pts = pkt.pts - pts_start_time[pkt.stream_index];
        pkt.dts = pkt.dts - dts_start_time[pkt.stream_index];
        if (pkt.dts > pkt.pts) {
            pkt.pts = pkt.dts;
        }

        pkt.stream_index = stream_map[pkt.stream_index];
        
        outStream = outFmtCtx->streams[pkt.stream_index];
        av_packet_rescale_ts(&pkt,inStream->time_base,outStream->time_base);
        pkt.pos = -1;
        // 把源文件读出来的packet，写入到目标文件中
        av_interleaved_write_frame(outFmtCtx,&pkt);
        av_packet_unref(&pkt);
    } 

    // 9、写多媒体文件尾到目标文件中
    av_write_trailer(outFmtCtx);
    
    // 10、将申请的资源释放掉
_ERROR:
    if (inFmtCtx) {
        avformat_close_input(&inFmtCtx);
        inFmtCtx = NULL;
    }
    if (outFmtCtx->pb) {
        avformat_free_context(outFmtCtx);
        outFmtCtx = NULL;
    }
    if (outFmtCtx) {
        avformat_free_context(outFmtCtx);
        outFmtCtx = NULL;
    }
    if (stream_map){
        av_free(stream_map);
    }
    if (dts_start_time) {
        av_free(dts_start_time);
    }
    if (pts_start_time){
        av_free(pts_start_time);
    }
    printf("hello world\n");
    return 0;
}
